-module(container).

-behaviour(gen_server).

%% API
-export([start_link/1]).
-export([deploy/2]).
-export([undeploy/2]).
-export([test_query/1]).
-export([query_instance_acc/1]).
-export([stop/1]).

%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2, code_change/3]).

-include("xengine.hrl").
-record(state, {container,apps}).

test_query(ContainerName)->
        	gen_server:call(list_to_atom(ContainerName) , {test_query } ).

query_instance_acc(ContainerName)->
            gen_server:call(  list_to_atom(ContainerName)  , {query_instance_acc }  , 20000).    

deploy(ContainerName,App)->
	gen_server:call(  list_to_atom(ContainerName)  , {deploy ,App}  , 5000).

stop(ContainerName)->
	gen_server:call(  list_to_atom(ContainerName)  , {stop }  , 5000).        

undeploy(ContainerName,all) ->
        gen_server:call(  list_to_atom(ContainerName)  , {undeploy} );
undeploy(ContainerName,AppName) when is_list(AppName)->
        case   configuration_manager:lookup(app,AppName) of
                []      ->
                        {error , "no such a app named "++ AppName };
                [App]  ->
                	gen_server:call(  list_to_atom(ContainerName)  , {undeploy ,App} )
        end.


%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link(Container) ->
%%    error_logger:info_msg("container:start_link Container=~p~n ",[Container]),
%%    gen_server:start_link(  ?MODULE, [Container], []).

    gen_server:start_link( {local, list_to_atom( Container#container.name ) }  , ?MODULE, [Container], []).

%%====================================================================
%% gen_server callbacks
%%====================================================================

%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%%                         {ok, State, Timeout} |
%%                         ignore               |
%%                         {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([Container]) ->
 %%   error_logger:info_msg("container:init Container=~p~n ",[Container]),
    case gen_server:call({agent_daemon , get_agent_node(Container#container.host)}, 
                                {regist,Container}) of
        ok ->
                    {ok, #state{container=Container, apps=[]}} ;
        {error , Reason } ->
                    { stop , Reason }
    end.



%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%%                                      {reply, Reply, State, Timeout} |
%%                                      {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, Reply, State} |
%%                                      {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({test_query},_From,State ) ->
        {reply ,  State  , State } ;
handle_call({stop}=Msg , _From , State ) ->  
        error_logger:info_msg("container:recving a  msg=~p~n",[Msg]),     
       	Container=State#state.container,
       { stop , normal , ok ,  State };
handle_call({undeploy,all}=Msg,_From,State)->
        error_logger:info_msg("container:recving a  msg=~p~n",[Msg]),    
	Container=State#state.container,
        { reply ,   gen_server:call({agent_daemon , get_agent_node(Container#container.host)},
                {undeploy , all  }, 5000),State };                   
handle_call({undeploy,App}=Msg , _From ,State )->
        error_logger:info_msg("container:recving a undeploy msg=~p~n",[Msg]),
	Container=State#state.container,
       {reply ,  gen_server:call({agent_daemon , get_agent_node(Container#container.host)},
                                {undeploy , App } ) , State };

handle_call({deploy,App} , _From ,State ) ->
	Container=State#state.container,
       {reply ,  gen_server:call({agent_daemon , get_agent_node(Container#container.host)},
                                {deploy , App }  , 5000 ) , State  };
handle_call({query_instance_acc} , _From ,State ) ->
	Container=State#state.container,
       {reply ,  gen_server:call({agent_daemon , get_agent_node(Container#container.host)},
                                {query_instance_acc }  , 15000 ) , State  };                                
handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast({deploy_report, {ok , App}} ,State)->
        error_logger:info_msg("container:deploy the app:~p to the container:~p success ~n",
                [App,State#state.container]),
        gen_server:cast(instance_manager,{deploy_report, {App,State#state.container}, ok }),                
        {noreply ,State };
handle_cast({deploy_report, {error , App, Reason}} ,State)->
        error_logger:info_msg("contaner:deploy the app:~p to the container:~p error , Reason:~p ~n",
                [App,State#state.container,Reason]),
        gen_server:cast(instance_manager,{deploy_report, {App,State#state.container}, {error , Reason } }),                
        {noreply ,State };        
handle_cast({ report, {InstanceRuntimes, ContainerRuntime}} , State ) ->
  error_logger:info_msg("recving a report cast : InstanceRuntimes=~p, ContainerRuntime=~p~n",[InstanceRuntimes,ContainerRuntime]),
        
        do_report(InstanceRuntimes,ContainerRuntime , State#state.container),
%%        configuration_manager:insert
        {noreply , State } ;
%%handle_cast({echo , Msg} , State) ->
%%        error_logger:info_msg("recving a echo cast : ~p~n",[Msg]),
%%        {noreply , State } ;

handle_cast(_Msg, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%%                                       {noreply, State, Timeout} |
%%                                       {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info( timeout, State ) ->
    { noreply , State }    ;
handle_info(_Info, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
%%     Container=State#state.container,
%%     gen_server:cast({agent_daemon , get_agent_node(Container#container.host)},
%%                                {unregist } ) ,
    ok.

%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
get_agent_node(Host)->
%%        error_logger:info_msg("Ip=~p~n",[Ip]),
        erlang:list_to_atom( "agent@"++Host)  .



do_report(InstanceRuntimes , ContainerRuntime , Container)->
        
      configuration_manager:insert(ContainerRuntime),
	io:format("ContainerRuntime:~p~n",[ContainerRuntime]),    
        io:format("InstanceRuntimes:~p~n",[InstanceRuntimes]),

      #container_runtime{runtime=Runtime }=ContainerRuntime,
      
      case  InstanceRuntimes of
                [] ->
                        %%如果没有部署任何应用负荷也挺高，说明有问题，需要报警
                        error_logger:info_msg("error , ContainerRuntime=~p,no instance runtime!!!~n",[ContainerRuntime]),
                       ok        ;
                _ ->
                       configuration_manager:insert(InstanceRuntimes),
			%%      error_logger:info_msg("container:Runtime=~p , CPU_HIGH_TRESHOLD=~p~n",[Runtime,?CPU_HIGH_THRESHOLD ]),
                      case  Runtime#runtime.cpu > ?CPU_HIGH_THRESHOLD   of

                               true ->
                                       error_logger:info_msg("~p :cpu overload : ~p~n",
                                       [Container#container.name , Runtime#runtime.cpu]),
                                        gen_server:cast(container_manager , {alarm_cpu_ceiling ,  
                                                                { InstanceRuntimes ,
                                                                  ContainerRuntime , 
                                                                  Container    }   
                                                                   } )    ;
                                false ->
                                        ok
      
                      end
                    %%  case  Runtime#runtime.cpu < ?CPU_LOW_THRESHOLD of
                      %%          true ->
    %%                %% error_logger:info_msg("~p :cpu low load : ~p~n",[Container#container.name , Runtime#runtime.cpu]),
                        %%               gen_server:cast(container_manager , {alarm_cpu_minimum ,  
                          %%                                      { InstanceRuntimes ,
                            %%                                      ContainerRuntime , 
                              %%                                    Container    }   
                                %%                                   } )    ;
                           %%     false -> 
                           %%     ok
                    %%  end
      end.



        







